#include "opencv.hpp"
#include "objdetect/objdetect.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>

#define DEFAULT_MODE      S_IRWXU | S_IRGRP |  S_IXGRP | S_IROTH | S_IXOTH

/** Utility function to create directory tree */
bool mkdirp(const char* path, mode_t mode = DEFAULT_MODE);

using namespace std;
using namespace cv;

#define WHITE_COLOR 254
#define X_SIZE 300
#define SUBIMAGES_DIR "./subimages/"

//#define SUBIMAGES_DIR ""

class Subimage{
public:
    int x;
    int y;
    int width;
    int heigh;
    
    int id;
    string filename;
    
    int votetotall;// all votes
    
    map<string,   int> votes;//votes for different methods
    vector<Rect> areas;
    void init(){

    }
    
    string getString(){
        
//        stringstream ssaa;
//        ssaa << "x = " << x << ",y = " << y << ",width = " << width << ",heigh = " << heigh << ",id = " << id << ",filename = " << filename << endl;
//        ssaa << "votetotall = " << votetotall << endl;
//        ssaa << "votes : "<< endl;
//        for (map<string,int>::iterator i = votes.begin(); i != votes.end(); i++){
//        	ssaa << i->first << " = " << i->second << endl;
//        }
//        String str = ssaa.str();
//        return str;
    	return "";
    }
};
vector<Subimage> subimages;


/** Function Headers */
void detectAndSave( Mat frame, Subimage * subimage);

/** Global variables */
String logo_cascade_name = "/Users/Peter/Documents/dev/workspaces/cpp_cdt/DartEllipse/src/dartcascade.xml";

CascadeClassifier logo_cascade;

string window_name = "Capture - Face detection";

//g++ face.cpp -o facexx.out $O_LIBS

void SobelX(cv::Mat &input, float **xMatrix, cv::Mat &blurredOutput);

void SobelY(cv::Mat &input, float **yMatrix, cv::Mat &blurredOutput);

void SobelMG(cv::Mat &input, float **xMatrix, float **yMatrix,
             cv::Mat &blurredOutput);

void normalization(int **a, int cols, int rows, cv::Mat &output);
void normalization(float **a, int cols, int rows, cv::Mat &output);
void CoinMGTH(cv::Mat &input, cv::Mat &blurredOutput);
void getGHTH(Mat Coin1,cv::Mat &coinMGTH);

Mat sharperMat(Mat img);
//void dodetect(string method, Mat frame,Mat frame_gray, Mat frame,vector<Rect> faces,double scaleFactor=1.1, int minNeighbors=3, int flags=0|CV_HAAR_SCALE_IMAGE, Size minSize=Size(1, 1), Size maxSize=Size(500,500));



void Myimwrite(string filename,InputArray img){
	string dir = SUBIMAGES_DIR;
	imwrite(dir.append(filename),img);
}


Mat savesubMatip(IplImage* rectImage,int x, int y, int width,int heigh,String filename){
	rectImage->roi=NULL;
	CvRect boundingBox={x,y,width,heigh};
	cvSetImageROI(rectImage,boundingBox);
    
    IplImage *img2 = cvCreateImage(cvGetSize(rectImage),
                                   rectImage->depth,
                                   rectImage->nChannels);
    IplImage* reSizedBox=cvCreateImage(cvSize(X_SIZE,X_SIZE),rectImage->depth,3);//width*2,heigh*2  i fix this size to make the target pictures in single size, make later filter easier.
    
	/* copy subimage */
	cvCopy(rectImage, img2, NULL);
    
    cvResize(img2,reSizedBox,CV_INTER_LINEAR);
    
	/* always reset the Region of Interest */
	cvResetImageROI(rectImage);
	string dir = SUBIMAGES_DIR;
	dir.append(filename);
	cvSaveImage(dir.c_str(), reSizedBox);
    
    Mat mat(reSizedBox);
    
    return mat;
    
}

Mat savesubMat(Mat src,int x, int y, int width,int heigh,String filename){
	IplImage srcx = IplImage(src);
	return savesubMatip(&srcx,x,y,width,heigh,filename);
}

void makeSubImages(Mat src){
    Mat src_gray;
    if( !src.data )
    { return; }
    /// Convert it to gray
    cvtColor( src, src_gray, CV_BGR2GRAY );
    /// Reduce the noise so we avoid false circle detection
    GaussianBlur( src_gray, src_gray, Size(5, 5), 0, 0 );
    
    
  //  Canny( src_gray, src_gray, 5, 70, 3 );
     //Canny( src_gray, src_gray, 100, 200, 3);
    
    
    vector<Vec3f> circles;
    /// Apply the Hough Transform to find the circles
    HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 2, src_gray.rows/8, 90, 100, src_gray.rows/10, src_gray.rows/2 );//117, 23  //src_gray.rows/8, 80, 50, src_gray.rows/8, src_gray.rows/2
    
    int param_1 = 150;
//    while (circles.size()>10) {
//        /*
//         src_gray: Input image (grayscale)
//         circles: A vector that stores sets of 3 values: x_{c}, y_{c}, r for each detected circle.
//         CV_HOUGH_GRADIENT: Define the detection method. Currently this is the only one available in OpenCV
//         dp = 1: The inverse ratio of resolution
//         min_dist = src_gray.rows/8: Minimum distance between detected centers
//         param_1 = 200: Upper threshold for the internal Canny edge detector
//         param_2 = 100*: Threshold for center detection.
//         min_radius = 0: Minimum radio to be detected. If unknown, put zero as default.
//         max_radius = 0: Maximum radius to be detected. If unknown, put zero as default
//         */
//         HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 2, src_gray.rows/8, param_1++, 150, src_gray.rows/10, src_gray.rows/2 );
//    }
    
    int id = 0;
    /// Draw the circles detected
    for( size_t i = 0; i < circles.size(); i++ )
    {
        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);
                
        //save sub image
        int x = cvRound(circles[i][0])-radius;
        int y = cvRound(circles[i][1])-radius;
        int width = radius*2;
        int heigh = radius*2;
        
        if(x <0 || y < 0){
            continue;
        }
        
//        if((x + width) > src_gray.size().width || (x + heigh) > src_gray.size().height){
//             continue;
//        }
        stringstream ssaa;
        ssaa << id << "__" << x << "_" << y << "_" << width << "_" << heigh << ".jpg";
//        ssaa << id << ".jpg";
        String str = ssaa.str();
        Mat subMat = savesubMat(src,x,y,width,heigh,str);
        Subimage subi;
        subi.x = x;
        subi.y = y;
        subi.width = width;
        subi.heigh = heigh;
        subi.id = id++;
        subi.filename = str;
        subi.votetotall = 0;
        //init
        subi.areas = vector<Rect>(100);
        subi.votes = map<string,   int> ();
        subimages.push_back(subi);
    }
}

void checkDir(){
//	CreateDirectory(SUBIMAGES_DIR,NULL);
//	RemoveDirectory(SUBIMAGES_DIR);
//	CreateDirectory(SUBIMAGES_DIR,NULL);
	string dir = SUBIMAGES_DIR;
//	rmdir(dir.c_str());
	mkdirp(dir.c_str());

}
/** @function main */
int mainx( int argc, const char** argv )
{
	checkDir();
	CvCapture* capture;
	Mat frame = imread(argv[1], CV_LOAD_IMAGE_COLOR);
    makeSubImages(frame);
    
    for( int i = 0; i < subimages.size(); i++ )
	{
        cout<<subimages[i].getString()<<endl;
    }
    
//
	if( !logo_cascade.load( logo_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };

    for( int i = 0; i < subimages.size(); i++ )
	{
//        cout<<subimages[i].getString()<<endl;
    	string dir = SUBIMAGES_DIR;
        detectAndSave( imread(dir.append(subimages[i].filename), CV_LOAD_IMAGE_COLOR), &(subimages[i]));
    }
    cout<< "====********** finished detect and save" << endl;
    for( int i = 0; i < subimages.size(); i++ )
	{
        //if(subimages[i].votetotall > 2){
//        	if(subimages[i].areas.empty() ){
//        		cout << "subimages[i].areas is null"<< endl;
//        	}
//        	for(int j = 0; j < subimages[i].areas.size();j++){
//        	    		Rect rect = subimages[i].areas[j];
//        				rectangle(frame, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar( 0, 255, 255 ), 3);
//        	    	}
       // }



        cout << subimages[i].getString() << endl;

    }

    for( int i = 0; i < subimages.size(); i++ )
	{
    	if(subimages[i].votetotall > 0){// change this for the threshold of vote for each circle
			for(int j = 0; j < subimages[i].areas.size();j++){
				Rect rect = subimages[i].areas[j];
				//if(rect.width > frame.size().width/30){
					rectangle(frame, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar( 0, 255, 255 ), 3);
					//TODO offer this to vote system.
				//}
			}
    	}
	}



    Myimwrite( "xxxxxxx.jpg", frame );

	return 0;
}

Rect localToGlobel(Subimage * subimage,Rect rect){
	//300   X_SIZE
	//get image's real size from the class
	int x = (*subimage).x;
	int y = (*subimage).y;
	int w = (*subimage).width;
	int h = (*subimage).heigh;

	int rx = rect.x;
	int ry = rect.y;
	int rw = rect.width;
	int rh = rect.height;

	int rrx = rect.x;
	int rry = rect.y;
	int rrw = rect.width;
	int rrh = rect.height;

	//scale
	rrx = rx * w / X_SIZE;
	rry = ry * h / X_SIZE;
	rrw = rw * w / X_SIZE;
	rrh = rh * h / X_SIZE;

	rrx = rrx + x;
	rry = rry + y;
	return Rect(rrx,rry,rrw,rrh);
}

void dodetect(string method,Subimage * subimage, Mat frame,Mat frame_gray,vector<Rect> faces,double scaleFactor=1.1, int minNeighbors=3, int flags=0|CV_HAAR_SCALE_IMAGE, Size minSize=Size(1, 1), Size maxSize=Size(500,500)){
	frame = frame.clone();
    string filename = "xxx";
    filename.append((*subimage).filename);
    
    //-- Detect faces
	logo_cascade.detectMultiScale( frame_gray, faces, scaleFactor, minNeighbors, flags, minSize, maxSize );
    
//	for( int i = 0; i < faces.size(); i++ )
//	{
//		rectangle(frame, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar( 0, 255, 0 ), 2);
//	}
//    if(faces.size() > 0){
//        string temp;
//        stringstream ss;
//        ss<<faces.size();
//        temp.append("x");
//        temp.append(ss.str());
//        temp.append("x");
//        temp.append("_");
//        temp.append(method);
//        temp.append("_");
//        temp.append(subimage.filename);
//        filename = temp;
//        subimage.votetotall = subimage.votetotall + faces.size();
//        subimage.votes[method] = faces.size();
//    }
//    
//    
//    std::cout << filename << std::endl;
//	//-- Save what you got
//	Myimwrite( filename, frame );
    
    
    //----------- distinct
    std::vector<Rect> realFaces;
    if(faces.size() > 0){
//        faces[0];
        realFaces.push_back(faces[0]);
        int index = 1;
        int flag = 0;
        for( int i = 0; i < faces.size(); i++ )
        {
            
            int ax = faces[i].x;
            int ay = faces[i].y;
            int aw = faces[i].width;
            int ah = faces[i].height;
            int acenterx = ax + aw/2;
            int acentery = ay + ah/2;
            int j = 0;
            for (j = 0; j< realFaces.size(); j++) {
                int bx = realFaces[j].x;
                int by = realFaces[j].y;
                int bw = realFaces[j].width;
                int bh = realFaces[j].height;
                int bcenterx = bx + bw/2;
                int bcentery = by + bh/2;
                if(acenterx > bx && acenterx < (bx + bw) && acentery > by && acentery < (by + bh)){// a in b, b bigger.
                    if(aw < bw || ah < bh){
                        flag = 1;// no change
                        break;
                    }else{
                        flag = 2;// a is the bigger one , switch them, put a into b's place.
                        break;
                    }
                }
                
                if(bcenterx > ax && bcenterx < (ax + aw) && bcentery > ay && bcentery < (ay + ah)){
                    if(bw<aw||bh<ah){
                        flag = 2;
                        break;
                    }else{
                        flag = 1;
                        break;
                    }
                }
            }
            if(flag == 1){
                
            }else if(flag == 2){
                realFaces[j] = faces[i];
            }else{
                realFaces[index] = faces[i];
                index++;
            }
            flag = 0;
        }
        
        
    }
    
    
    
    for( int i = 0; i < realFaces.size(); i++ )
	{
		rectangle(frame, Point(realFaces[i].x, realFaces[i].y), Point(realFaces[i].x + realFaces[i].width, realFaces[i].y + realFaces[i].height), Scalar( 0, 255, 0 ), 2);
		//if(realFaces.size() > 2){
			 (*subimage).areas.push_back(localToGlobel(subimage,realFaces[i]));

		//}
	}







    if(realFaces.size() > 0){
        string temp;
        stringstream ss;
        ss<<realFaces.size();
        temp.append("x");
        //temp.append(ss.str());
        temp.append("x");
        temp.append("_");
        temp.append(method);
        temp.append("_");
        temp.append((*subimage).filename);
        filename = temp;
        cout<<"---------------------------" << (*subimage).votetotall <<endl;
        (*subimage).votetotall = (*subimage).votetotall + realFaces.size();
        cout<<"---------------------------" << (*subimage).votetotall <<endl;

        //subimage.votes[method] = realFaces.size();
        (*subimage).votes.insert(map<string, int>::value_type(method, realFaces.size()));

    }
    
    
    std::cout << filename << std::endl;
	//-- Save what you got
	Myimwrite( filename, frame );
    
    
}

/** @function detectAndSave */
void detectAndSave( Mat frame, Subimage * subimage)
{
	std::vector<Rect> faces;
	Mat frame_gray;
    Mat frame_gray_guass;
    Mat frame_gray_sharp;
    Mat frame_gray_GHTH;
    
	cvtColor( frame, frame_gray, CV_BGR2GRAY );
	equalizeHist( frame_gray, frame_gray );
    
    GaussianBlur( frame_gray, frame_gray_guass, Size (11,11),0,0 );//gaussian
    string methodstr = "Nothing";
    dodetect(methodstr,subimage,frame,frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(80, 80));
    
    
    methodstr = "GaussianBlur";
    dodetect(methodstr,subimage,frame,frame_gray_guass, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(80, 80));
    
    methodstr = "sharper";
    frame_gray_sharp = sharperMat(frame_gray);// sharper
    dodetect(methodstr,subimage,frame,frame_gray_sharp, faces, 1.1, 5 , 0|CV_HAAR_SCALE_IMAGE, Size(80, 80)); // because after sharpered some noise can cause some small wrong detected erea. hence i raise te mini area.
//
    //frame_gray_GHTH = frame_gray;// check this later for non point exception.
    methodstr = "GHTH";
    getGHTH(frame_gray,frame_gray_GHTH);//sobel magnitude threshold
    dodetect(methodstr,subimage,frame,frame_gray_GHTH, faces, 1.1, 10 , 0|CV_HAAR_SCALE_IMAGE, Size(150, 150));
    
    methodstr = "guss_sharper";
    frame_gray_sharp = sharperMat(frame_gray_guass);// sharper
    dodetect(methodstr,subimage,frame,frame_gray_sharp, faces, 1.1, 5 , 0|CV_HAAR_SCALE_IMAGE, Size(80, 80)); // because after sharpered some noise can cause some small wrong detected erea. hence i raise te mini area.
    //
    methodstr = "guss_sharper_GHTH";// check this later for non point exception.
    getGHTH(frame_gray_sharp,frame_gray_GHTH);//sobel magnitude threshold
    dodetect(methodstr,subimage,frame,frame_gray_GHTH, faces, 1.1, 10 , 0|CV_HAAR_SCALE_IMAGE, Size(150, 150));
}



Mat sharperMat(Mat img){
    Mat imgResult,imgLaplacian;
    Mat kernel = (Mat_<float> (3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1); // another approximation of second derivate, more stronger
    
	// do the laplacian filtering as it is
	// well, we need to convert everything in something more deeper then CV_8U
	// because the kernel has some negative values,
	// and we can expect in general to have a Laplacian image with negative values
	// BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
	// so the possible negative number will be truncated
	filter2D(img, imgLaplacian, CV_32F, kernel);
	img.convertTo(img, CV_32F);
	imgResult = img - imgLaplacian;
    
	// convert back to 8bits gray scale
	imgResult.convertTo(imgResult, CV_8U);
//	imgLaplacian.convertTo(imgLaplacian, CV_8U);
    return imgResult;
    
}



///////=====================
///////=====================
///////=====================
///////=====================
///////=====================
///////=====================
///////=====================




void getGHTH(Mat Coin1,cv::Mat & coinMGTH){
    //---------------Dx
	cv::Mat coinDX;
	float **xMatrix = new float *[Coin1.rows];
	for (int i = 0; i < Coin1.rows; ++i) {
		xMatrix[i] = new float[Coin1.cols];
	}
    
	SobelX(Coin1, xMatrix, coinDX);
    
	//-----------------Dy
	cv::Mat coinDY;
	float **yMatrix = new float *[Coin1.rows];
	for (int i = 0; i < Coin1.rows; ++i) {
		yMatrix[i] = new float[Coin1.cols];
	}
    
	SobelY(Coin1, yMatrix, coinDY);
    
	//------------------MG
	cv::Mat coinMG;
	SobelMG(Coin1, xMatrix, yMatrix, coinMG);
    
	//-------------------MGTH
	CoinMGTH(coinMG, coinMGTH);
    
}





void normalization(int **a, int cols, int rows, cv::Mat &output) {
	double maxX = 0;
	double minX = 0;
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			int temp = a[i][j];
			if (temp >= maxX) {
				maxX = temp;
			}
			if (temp <= minX) {
				minX = temp;
			}
		}
	}
    
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			int sum = a[i][j];
			sum = sum - minX;
            
			double xxsum = (255 / (maxX - minX)) * sum;
			output.at<uchar> (i, j) = (uchar) xxsum;
		}
	}
}

void normalization(float **a, int cols, int rows, cv::Mat &output) {
	double maxX = 0;
	double minX = 0;
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			int temp = a[i][j];
			if (temp >= maxX) {
				maxX = temp;
			}
			if (temp <= minX) {
				minX = temp;
			}
		}
	}
    
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			int sum = a[i][j];
			sum = sum - minX;
            
			double xxsum = (255 / (maxX - minX)) * sum;
			output.at<uchar> (i, j) = (uchar) xxsum;
		}
	}
}
void SobelX(cv::Mat &input, float **xMatrix, cv::Mat &output) {
	int size = 3;
	// intialise the output using the input
	output.create(input.size(), input.type());
	// create the Gaussian kernel in 1D
	cv::Mat kX = cv::getGaussianKernel(size, -1);
	cv::Mat kY = cv::getGaussianKernel(size, -1);
    
	// make it 2D multiply one by the transpose of the other
	cv::Mat kernelx = kX * kY.t();
    
	//sobel kernel:  dx
	kernelx.at<double> (0, 0) = -1;
	kernelx.at<double> (0, 1) = 0;
	kernelx.at<double> (0, 2) = 1;
	kernelx.at<double> (1, 0) = -2;
	kernelx.at<double> (1, 1) = 0;
	kernelx.at<double> (1, 2) = 2;
	kernelx.at<double> (2, 0) = -1;
	kernelx.at<double> (2, 1) = 0;
	kernelx.at<double> (2, 2) = 1;
    
	cv::Mat kernel = kernelx;
    
	//CREATING A DIFFERENT IMAGE kernel WILL BE NEEDED
	//TO PERFORM OPERATIONS OTHER THAN GUASSIAN BLUR!!!
    
	// we need to create a padded version of the input
	// or there will be border effects
	int kernelRadiusX = (kernel.size[0] - 1) / 2;
	int kernelRadiusY = (kernel.size[1] - 1) / 2;
    
	cv::Mat paddedInput;
	cv::copyMakeBorder(input, paddedInput, kernelRadiusX, kernelRadiusX,
                       kernelRadiusY, kernelRadiusY, cv::BORDER_REPLICATE);
    
	for (int i = 0; i < input.rows; i++) {
		for (int j = 0; j < input.cols; j++) {
			double sum = 0.0;
			for (int m = -kernelRadiusX; m <= kernelRadiusX; m++) {
				for (int n = -kernelRadiusY; n <= kernelRadiusY; n++) {
					// find the correct indices we are using
					int imagex = i + 1 + m;
					int imagey = j + 1 + n;
					int kernelx = m + kernelRadiusX;
					int kernely = n + kernelRadiusY;
                    
					// get the values from the padded image and the kernel
					int imageval = (int) paddedInput.at<uchar> (imagex, imagey);
					double kernalval = kernel.at<double> (kernelx, kernely);
                    
					// do the multiplication
					sum += imageval * kernalval;
				}
			}
			// set the output value as the sum of the convolution
			xMatrix[i][j] = sum;
		}
	}
    
	normalization(xMatrix, input.cols, input.rows, output);
    
}

void SobelY(cv::Mat &input, float **yMatrix, cv::Mat &output) {
	int size = 3;
	// intialise the output using the input
	output.create(input.size(), input.type());
    
	// create the Gaussian kernel in 1D
	cv::Mat kX = cv::getGaussianKernel(size, -1);
	cv::Mat kY = cv::getGaussianKernel(size, -1);
    
	// make it 2D multiply one by the transpose of the other
	cv::Mat kernely = kX * kY.t();
    
	kernely.at<double> (0, 0) = -1;
	kernely.at<double> (0, 1) = -2;
	kernely.at<double> (0, 2) = -1;
	kernely.at<double> (1, 0) = 0;
	kernely.at<double> (1, 1) = 0;
	kernely.at<double> (1, 2) = 0;
	kernely.at<double> (2, 0) = 1;
	kernely.at<double> (2, 1) = 2;
	kernely.at<double> (2, 2) = 1;
    
	cv::Mat kernel = kernely;
    
	//CREATING A DIFFERENT IMAGE kernel WILL BE NEEDED
	//TO PERFORM OPERATIONS OTHER THAN GUASSIAN BLUR!!!
    
	// we need to create a padded version of the input
	// or there will be border effects
	int kernelRadiusX = (kernel.size[0] - 1) / 2;
	int kernelRadiusY = (kernel.size[1] - 1) / 2;
    
	cv::Mat paddedInput;
	cv::copyMakeBorder(input, paddedInput, kernelRadiusX, kernelRadiusX,
                       kernelRadiusY, kernelRadiusY, cv::BORDER_REPLICATE);
    
	//int a[1024][1024];// = { 0 };
    
	// now we can do the convoltion
	for (int i = 0; i < input.rows; i++) {
		for (int j = 0; j < input.cols; j++) {
			double sum = 0.0;
			for (int m = -kernelRadiusX; m <= kernelRadiusX; m++) {
				for (int n = -kernelRadiusY; n <= kernelRadiusY; n++) {
					// find the correct indices we are usingvoid GaussianBlurMG(cv::Mat &input,cv::Mat &inputy, int size, cv::Mat &blurredOutput)
					int imagex = i + 1 + m;
					int imagey = j + 1 + n;
					int kernelx = m + kernelRadiusX;
					int kernely = n + kernelRadiusY;
                    
					// get the values from the padded image and the kernel
					int imageval = (int) paddedInput.at<uchar> (imagex, imagey);
					double kernalval = kernel.at<double> (kernelx, kernely);
                    
					// do the multiplication
					sum += imageval * kernalval;
				}
			}
			// set the output value as the sum of the convolution
			//blurredOutput.at<uchar>(i, j) = (uchar) sum;
			yMatrix[i][j] = sum;
		}
	}
    
	normalization(yMatrix, input.cols, input.rows, output);
}

void SobelMG(cv::Mat &input, float **xMatrix, float **yMatrix, cv::Mat &output) {
	output.create(input.size(), input.type());
    
	int **mGMatrix = new int *[input.rows];
	for (int i = 0; i < input.rows; ++i) {
		mGMatrix[i] = new int[input.cols];
	}
	// now we can do the convoltion
	for (int i = 0; i < input.rows; i++) {
		for (int j = 0; j < input.cols; j++) {
            
			double imageval = xMatrix[i][j];
            
			double imagevaly = yMatrix[i][j];
            
			//blurredOutput.at<uchar>(i, j) = (uchar) sqrt(imageval * imageval + imagevaly * imagevaly);
			//blurredOutput.at<uchar>(i, j) =
			mGMatrix[i][j] = sqrt(imageval * imageval + imagevaly * imagevaly);
		}
	}
    
	normalization(mGMatrix, input.cols, input.rows, output);
	for (int i = 0; i < input.rows; ++i) {
		free(mGMatrix[i]);
	}
	free(mGMatrix);
}

void CoinMGTH(cv::Mat &input, cv::Mat &output) {
	output.create(input.size(), input.type());
	for (int i = 0; i < input.rows; i++) {
		for (int j = 0; j < input.cols; j++) {
			uchar xxsum = input.at<uchar> (i, j);
			if (xxsum > 80) {
				output.at<uchar> (i, j) = WHITE_COLOR;
			} else {
				output.at<uchar> (i, j) = 0;
			}
		}
	}
    
}




bool mkdirp(const char* path, mode_t mode) {
  // const cast for hack
  char* p = const_cast<char*>(path);

  // Do mkdir for each slash until end of string or error
  while (*p != '\0') {
    // Skip first character
    p++;

    // Find first slash or end
    while(*p != '\0' && *p != '/') p++;

    // Remember value from p
    char v = *p;

    // Write end of string at p
    *p = '\0';

    // Create folder from path to '\0' inserted at p
    if(mkdir(path, mode) == -1 && errno != EEXIST) {
      *p = v;
      return false;
    }

    // Restore path to it's former glory
    *p = v;
  }

  return true;
}








